# coding:utf8

import os
import sys
import imp
import time, datetime
import logging
from flask import Flask, session, request, jsonify, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_cors import CORS, cross_origin
from logging.handlers import RotatingFileHandler
from werkzeug.datastructures import FileStorage
from werkzeug.routing import BaseConverter
import pymongo
import redis
from setting import *
from flask_session import Session
import copy
from sqlalchemy  import or_, and_
from sqlalchemy.sql import func
from flask_debugtoolbar import DebugToolbarExtension

#sys.setdefaultencoding("utf-8")
# 设置递归数量
sys.setrecursionlimit(100000)
BASE_DIR = os.path.abspath(os.path.dirname(__file__)).replace("\\", "/")
getpath = lambda path: os.path.join(BASE_DIR, path).replace("\\", "/")

"""
加入自定义目录到环境中
"""
APPENDED_PATH = ['admin', 'apis', 'home', 'models', 'utils']
for module in APPENDED_PATH:
    sys.path.insert(0, getpath(module))

"""
Flask配置
"""
app = Flask(__name__, template_folder="templates", static_folder="static")
app.secret_key="4#oijjmgQicapi7ftP3ehRTzvrAh@6Hd"
# app.debug = DEBUG
app.debug =True
app.config["HOST"] = HOST
app.config["PORT"] = PORT
app.config["THREADED"] = THREADED
app.config['JSON_AS_ASCII'] = False
toolbar = DebugToolbarExtension(app)
"""
flask session
"""
app.config['SESSION_TYPE'] = 'redis'    # session类型为redis
app.config['SESSION_PERMANENT'] = True    # 是否关闭浏览器就使session失效
app.config['SESSION_USE_SIGNER'] = False    # 是否对发送到浏览器cookie上的session值进行加密
app.config['SESSION_KEY_PREFIX'] = 'session'    # 保存在session中的值的前缀
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port='6379')

Session(app)

"""
JinJa配置
"""
app.jinja_env.variable_start_string = '{{ '
app.jinja_env.variable_end_string = ' }}'

"""
调试日志
"""
if not app.debug:
    log_file = os.path.join(getpath("log"), "applog.log")
    file_handler = RotatingFileHandler(log_file, "a", 1 * 1024 * 1024, 10)
    file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]"))
    app.logger.setLevel(logging.INFO)
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.info("appserver startup")
else:
    pass

"""
支持正则URL
"""

# 写个转换器类
class RegexConverter(BaseConverter):
    def __init__(self, url_map, *item):
        super(RegexConverter, self).__init__(url_map)
        self.regex = item[0]

# 添加到flask中
app.url_map.converters['regex'] = RegexConverter

"""
ORM 数据库配置
"""
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_BINDS"] = SQLALCHEMY_BINDS
app.config["SQLALCHEMY_ECHO"] = SQLALCHEMY_ECHO
app.config["SQLALCHEMY_NATIVE_UNICODE"] = SQLALCHEMY_NATIVE_UNICODE
app.config["SQLALCHEMY_POOL_SIZE"] = SQLALCHEMY_POOL_SIZE
app.config["SQLALCHEMY_POOL_TIMEOUT"] = SQLALCHEMY_POOL_TIMEOUT
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
db_store = SQLAlchemy(app)
# 数据库同步
migrate = Migrate(app=app, db=db_store, directory="migrations")


def to_dict(self):
    return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}


# def from_dict(self, source):
#     if "ParentId" in source:
#         source["parent_id"] = source.pop("ParentId")
#     if "Level" in source:
#         source["depth"] = source.pop("Level")
#     for k in source:
#         try:
#             getattr(self, k)
#         except AttributeError as e:
#             raise RuntimeError("数据格式错误")
#         setattr(self, k, source[k])

def from_dict(self, source):
    if "parent_id" in source:
        source["parent_id"] = source.pop("parent_id")
    if "level" in source:
        source["depth"] = source.pop("level")
    for k in source:
        try:
            getattr(self, k)
        except AttributeError as e:
            raise RuntimeError("数据格式错误")
        setattr(self, k, source[k])


db_store.Model.to_dict = to_dict
db_store.Model.from_dict = from_dict


def execute_sql(sql, bind="main"):
    sql_engine = db_store.get_engine(app, bind=bind)
    return sql_engine.execute(sql)


def sql_row_to_dict(row):
    result={}
    n = len(row._parent.keys)
    for num in range(0, n):
        result[row._parent.keys[num]]=row[num]
    return result


"""
MongoDB配置
"""
mongo_store = pymongo.MongoClient('%s:%s' % (MONGO_HOST, MONGO_PORT), connectTimeoutMS=5000)

"""
Redis配置
"""
redis_store = {}
for rd in REDIS_DB:
    rd_name = rd[0]
    rd_db = rd[1]
    pool = redis.ConnectionPool(host=REDIS_HOST, port=REDIS_PORT, db=rd_db, password=REDIS_PWD)
    redisc = redis.StrictRedis(connection_pool=pool, socket_connect_timeout=REDIS_TIMEOUT, socket_timeout=REDIS_TIMEOUT,
                               charset="utf-8", decode_responses=True)
    redis_store[rd_name] = redisc

"""
跨域处理
"""
cors = CORS(app)

"""
注册蓝图
"""
from home.index import mod as home_index_mod

app.register_blueprint(home_index_mod)

from home.system import mod as home_system_mod

app.register_blueprint(home_system_mod)

from admin.core.user import mod as user_mod

app.register_blueprint(user_mod)

from admin.core.department import mod as department_mod

app.register_blueprint(department_mod)

from admin.core.organization import mod as organization_mod

app.register_blueprint(organization_mod)

from admin.core.area import mod as area_mod

app.register_blueprint(area_mod)

from admin.core.button import mod as button_mod

app.register_blueprint(button_mod)

from admin.core.device import mod as device_mod

app.register_blueprint(device_mod)

from admin.core.device_type import mod as device_type_mod

app.register_blueprint(device_type_mod)

from admin.core.dict_category import mod as dict_category_mod

app.register_blueprint(dict_category_mod)

from admin.core.dict import mod as dict_mod

app.register_blueprint(dict_mod)

from admin.core.district import mod as district_mod

app.register_blueprint(district_mod)

from admin.core.district_item import mod as district_item_mod

app.register_blueprint(district_item_mod)

from admin.core.facility import mod as facility_mod

app.register_blueprint(facility_mod)

from admin.core.facility_type import mod as facility_type_mod

app.register_blueprint(facility_type_mod)

from admin.core.module import mod as module_mod

app.register_blueprint(module_mod)

# from admin.core.index import mod as core_index_mod
#
# app.register_blueprint(core_index_mod)

from admin.core.quarter import mod as core_quarter_mod

app.register_blueprint(core_quarter_mod)

from admin.core.device_group import mod as core_device_group_mod

app.register_blueprint(core_device_group_mod)

from admin.core.sensor import mod as core_sensor_mod

app.register_blueprint(core_sensor_mod)

from admin.core.sensor_type import mod as core_sensor_type_mod

app.register_blueprint(core_sensor_type_mod)

from admin.core.sensor_group import mod as core_sensor_group_mod

app.register_blueprint(core_sensor_group_mod)

from admin.core.device_info import mod as core_device_info_mod

app.register_blueprint(core_device_info_mod)

from admin.core.patrol_recorder import mod as core_patrol_recorder_mod

app.register_blueprint(core_patrol_recorder_mod)

from admin.core.patrol_manage import mod as core_patrol_manage_mod

app.register_blueprint(core_patrol_manage_mod)

from admin.core.remote_host import mod as core_remote_host_mod

app.register_blueprint(core_remote_host_mod)

from admin.core.maintenance import mod as core_maintenance_mod

app.register_blueprint(core_maintenance_mod)

from admin.core.task import mod as core_task_mod

app.register_blueprint(core_task_mod)

from admin.iot.gateway import mod as iot_gateway_mod

app.register_blueprint(iot_gateway_mod)

from admin.iot.sensor import mod as iot_sensor_mod

app.register_blueprint(iot_sensor_mod)

from admin.iot.sensor_type import mod as iot_sensor_type_mod

app.register_blueprint(iot_sensor_type_mod)

from admin.core.point import mod as point_mod

app.register_blueprint(point_mod)



#  我的练习
from wo.aa import mod as wo_mod
app.register_blueprint(wo_mod)


"""
HTTP错误处理
"""


@app.errorhandler(400)
@app.errorhandler(403)
@app.errorhandler(403)
@app.errorhandler(500)
def internal_error(error):
    print(error)
    return error


"""
请求拦截
"""

# 请求钩子,类似与django的中间件,所有的请求进来之前都要经过它,所以这里可以统一管理,例如做登陆认证
@app.before_request
def before_request():
    pass

